﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WMM.Tapioca.Taxonomy;
using WMM.Tapioca.Linkbase;
using WMM.Tapioca;
using WMM.Tapioca.Validate;
using System.Xml;
using System.IO;
using System.Configuration;
using System.Net;
using WMM.Tapioca.Instance;
using WMM.Tapioca.Formula;
using WMM.Tapioca.Utilities;

namespace WMM.Test.Tapioca
{
    [TestClass]
    public class FormulaCONFREC20111024Test
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        static XmlCachingResolver resolver;

        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            bool useProxy = Boolean.Parse(ConfigurationManager.AppSettings["UseProxy"]);
            resolver = new XmlCachingResolver(true, useProxy);    
        }

		private int thisTestsPassed;

        public FormulaCONFREC20111024Test()
		{
		}
		
		[TestMethod]
        [Description("Formula-CONF-REC-2011-10-24")]
        public void FormulaCONFREC20111024Testcases()
		{
			thisTestsPassed = 0;
			var conformanceXmlSource = ConfigurationManager.AppSettings["ConformanceFormula"];
			var conformanceXmlSourcePath = Path.GetDirectoryName(conformanceXmlSource);
			var conformanceXmlDocument = new XmlDocument();
			conformanceXmlDocument.Load(conformanceXmlSource);

            XmlNodeList TestcasesNodes = conformanceXmlDocument.SelectNodes("//testcases");

            foreach (XmlNode TestcasesNode in TestcasesNodes)
            {
                string root = "";
                foreach (XmlAttribute CurrentAttribute in TestcasesNode.Attributes)
                {
                    if (CurrentAttribute.LocalName.Equals("root"))
                    {
                        root = CurrentAttribute.Value;
                    }            
                }

                XmlNodeList TestcaseNodes = TestcasesNode.SelectNodes("testcase");
                
                foreach (XmlNode TestcaseNode in TestcaseNodes)
                {
                    ExecuteTestcase(conformanceXmlSourcePath + "//" + root, TestcaseNode);
                }
            }
		}

		/// <summary>
		/// Executes the test case referenced in the supplied test case node.
		/// </summary>
		/// <param name="ConformanceXmlSourcePath">
		/// The path to the conformance suite.
		/// </param>
		/// <param name="TestcaseNode">
		/// A reference to one of the &lt;testcase&gt; elements in the root test suiteb ocument.
		/// </param>
		private void ExecuteTestcase(string ConformanceXmlSourcePath, XmlNode TestcaseNode)
		{
			var uriAttribute = TestcaseNode.Attributes["uri"];
			var testcaseXmlSource = uriAttribute.Value;
			var testcaseXmlSourceFullPathBuilder = new StringBuilder();
			testcaseXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", ConformanceXmlSourcePath, Path.DirectorySeparatorChar, testcaseXmlSource);
			var testcaseXmlSourceFullPath = testcaseXmlSourceFullPathBuilder.ToString();
			var testcaseXmlSourceDirectory = Path.GetDirectoryName(testcaseXmlSourceFullPath);
			var testcaseXmlDocument = new XmlDocument();
			testcaseXmlDocument.Load(testcaseXmlSourceFullPath);

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(testcaseXmlDocument.NameTable);
            nsmgr.AddNamespace("c", "http://xbrl.org/2008/conformance");
            var variationNodes = testcaseXmlDocument.SelectNodes("//c:variation", nsmgr);

			foreach (XmlNode VariationNode in variationNodes)
			{
				ExecuteVariation(testcaseXmlSourceDirectory, VariationNode);
			}
		}

		
		private void ExecuteVariation(string TestcaseXmlSourceDirectory, XmlNode VariationNode)
		{
            XbrlException VariationException = null;
            bool Validated = true;

			var currentVariation = new TestVariation2(VariationNode);

            if (currentVariation.ReadInstanceFirst)
            {
                if (string.IsNullOrEmpty(currentVariation.Instance) == true)
                    return;

                var instanceXmlSourceFullPathBuilder = new StringBuilder();
                instanceXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", TestcaseXmlSourceDirectory, Path.DirectorySeparatorChar, currentVariation.Instance);
                var instanceXmlSourceFullPath = instanceXmlSourceFullPathBuilder.ToString();

                try
                {
                    var newInstanceDocument = new InstanceDocument(instanceXmlSourceFullPath, resolver);
                    
                    XbrlManager xbrlManager = new XbrlManager(newInstanceDocument);                   
                    xbrlManager.Validate();

                    if (TestcaseXmlSourceDirectory.Contains("10000 Formula"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }
                    if (TestcaseXmlSourceDirectory.Contains("20000 Variables"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }

                    if (TestcaseXmlSourceDirectory.Contains("30000 Assertions"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            //Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }

                    if (TestcaseXmlSourceDirectory.Contains("40000 Filters"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }

                    if (TestcaseXmlSourceDirectory.Contains("60000 Extensions"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            //Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }

                    if (TestcaseXmlSourceDirectory.Contains("70000 Linkbase"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }

                    if (TestcaseXmlSourceDirectory.Contains("examples"))
                    {
                        if (currentVariation.Error.Length > 0)
                        {
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                        }
                        else
                        { // create instance
                            Validated = newInstanceDocument.Dts.ValidatedFormula;
                            currentVariation.ValidityExpected = true;
                        }
                    }
                    
                }
                catch (Exception ex)
                {
                    log.Error("Error:", ex);
                    log.Error(ex.StackTrace);
                    Validated = false;
                }
            }


            if (currentVariation.ReadXsdFirst || currentVariation.ReadLinkbaseFirst)
            {
                try
                {
                    DTS dts = null;
                    TaxonomySchema ts = null;

                    if (currentVariation.ReadXsdFirst)
                    {
                        if (!string.IsNullOrEmpty(currentVariation.Xsd))
                        {
                            var schemaXmlSourceFullPathBuilder = new StringBuilder();
                            schemaXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", TestcaseXmlSourceDirectory, Path.DirectorySeparatorChar, currentVariation.Xsd);

                            string XsdSourceFullPath = schemaXmlSourceFullPathBuilder.ToString();

                            ts = new TaxonomySchema(null, XsdSourceFullPath, null, "", resolver);

                            dts = new DTS(ts, resolver);
                        }
                    }               
                
                    if (currentVariation.ReadLinkbaseFirst)
                    {
                        if (!string.IsNullOrEmpty(currentVariation.Linkbase))
                        {
                            var linkbaseXmlSourceFullPathBuilder = new StringBuilder();
                            linkbaseXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", TestcaseXmlSourceDirectory, Path.DirectorySeparatorChar, currentVariation.Linkbase);
                            string LinkbaseSourceFullPath = linkbaseXmlSourceFullPathBuilder.ToString();
                            LinkbaseDocument linkbase = new LinkbaseDocument(dts, ts.XmlSchema, "", LinkbaseSourceFullPath, "", resolver);

                            dts = new DTS(linkbase, resolver);

                            log.Info("Creating LinkbaseDocument: " + linkbase.FileName);
                            dts.LinkbaseDocuments.Add(linkbase);
                        }
                    }

                    XbrlManager xbrlManager = new XbrlManager(null);

                    if (TestcaseXmlSourceDirectory.Contains("10000 Formula"))
                    {
                        ValidateLinkbaseFormula vlf = new ValidateLinkbaseFormula(dts);
                        FormulaProcessor vf = new FormulaProcessor(dts, "Formula-StaticAnalysis");
                        Validated = dts.ValidatedFormula;
                    }

                    if (TestcaseXmlSourceDirectory.Contains("20000 Variables"))
                    {
                        ValidateLinkbaseFormula vlf = new ValidateLinkbaseFormula(dts);
                        FormulaProcessor vf = new FormulaProcessor(dts, "Variable-StaticAnalysis");
                        Validated = dts.ValidatedFormula;
                    }

                    if (TestcaseXmlSourceDirectory.Contains("30000 Assertions"))
                    {
                        FormulaProcessor vf = new FormulaProcessor(dts, false);
                        Validated = dts.ValidatedFormula;
                    }

                    if (TestcaseXmlSourceDirectory.Contains("40000 Filters"))
                    {
                        FormulaProcessor vf = new FormulaProcessor(dts, false);
                        Validated = dts.ValidatedFormula;
                    }

                    if (TestcaseXmlSourceDirectory.Contains("60000 Extensions"))
                    {
                        FormulaProcessor vf = new FormulaProcessor(dts, false);
                        Validated = dts.ValidatedFormula;
                    }

                    if (TestcaseXmlSourceDirectory.Contains("70000 Linkbase"))
                    {
                        FormulaProcessor vf = new FormulaProcessor(dts, false);
                        Validated = dts.ValidatedFormula;
                    }
                }
                catch (Exception ex)
                {
                    log.Error("Error:", ex);
                    log.Error(ex.StackTrace);
                    Validated = false;
                }
            }

            if ((Validated == true) && (currentVariation.ValidityExpected == false))
				AnnounceTestFailure(currentVariation);
            if ((Validated == false) && (currentVariation.ValidityExpected == true))
				AnnounceTestFailure(currentVariation, VariationException); 
			thisTestsPassed++;
		}

		//-------------------------------------------------------------------------------
		//-------------------------------------------------------------------------------
		private void AnnounceTestFailure(TestVariation2 CurrentVariation, Exception VariationException)
		{
			var failMessage = new StringBuilder();

			failMessage.AppendFormat("Instance: {0}{1}", CurrentVariation.Instance, Environment.NewLine);
			failMessage.AppendFormat("Name: {0}{1}", CurrentVariation.Name, Environment.NewLine);
			failMessage.AppendFormat("Description: {0}", CurrentVariation.Description);
			if (VariationException != null)
			{
				failMessage.AppendFormat("{0}Exception Type: {1}{2}", Environment.NewLine, VariationException.GetType().ToString(), Environment.NewLine);
				failMessage.AppendFormat("Exception Description: {0}", VariationException.Message);
			}
			Assert.Fail(failMessage.ToString());
		}

		//-------------------------------------------------------------------------------
		//-------------------------------------------------------------------------------
		private void AnnounceTestFailure(TestVariation2 CurrentVariation)
		{
			AnnounceTestFailure(CurrentVariation, null);
		}
    }
}
